package net.xdclass.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.annotation.RepeatSubmit;
import net.xdclass.constant.RedisKey;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.exception.BizException;
import net.xdclass.interceptor.LoginInterceptor;
import net.xdclass.model.LoginUser;
import net.xdclass.service.RepeatSubmitHandler;
import net.xdclass.util.CommonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author Allen
 * @version 1.0
 * @date 2022/11/22 09:20
 */
@Service
@Slf4j
public class RepeatSubmitHandlerImpl implements RepeatSubmitHandler {

	@Autowired
	private RedisTemplate redisTemplate;

	@Resource
	private LockTemplate lockTemplate;

	@Override
	public Boolean byToken(ProceedingJoinPoint proceedingJoinPoint) {

		LoginUser loginUser = LoginInterceptor.threadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

		log.info("token防重复");
		String header = request.getHeader("request-token");
		if (StrUtil.isBlank(header)) {
			throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
		} else {
			String key = String.format(RedisKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getAccountNo(), header);
			Boolean delete = redisTemplate.delete(key);
			if (Boolean.FALSE.equals(delete)) {

				log.warn("重复提交的请求 by token");
				return Boolean.FALSE;
			}
		}
		return Boolean.TRUE;


	}

	@Override
	public Boolean byLock(ProceedingJoinPoint proceedingJoinPoint) {

		log.info("参数防重复");
		HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

		String ipAddr = CommonUtil.getIpAddr(request);

		MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
		Method method = signature.getMethod();
		String className = method.getDeclaringClass().getName();

		RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
		RepeatSubmit.Type type = annotation.limitType();
		long lockTime1 = annotation.lockTime();
		log.info("反射获取的注解信息：{},{}", type.name(), lockTime1);
		LoginUser loginUser = LoginInterceptor.threadLocal.get();

		String key = StrUtil.format("shop:repeat-submit:{}:{}:{}:{}", ipAddr, className, method.getName(), loginUser.getAccountNo());
		LockInfo lock = lockTemplate.lock(key, lockTime1 * 1000, 0L);
		if (ObjectUtil.isNull(lock)) {
			log.warn("重复提交请求 by lock");
			return Boolean.FALSE;
		}
		return Boolean.TRUE;

	}
}